﻿using System;
using System.Drawing;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;

namespace NetShips {
    /// <summary>
    /// Vytváří jedno hrací pole.
    /// </summary>
    public class GameField: System.Windows.Forms.Panel {
        private const int DEF_VELIKOST_POLE = 10;
        private const int DEF_ROZMER_BODU = 28;

        delegate void dSetBorderStyle(BorderStyle style);


        private static Point _fieldSize = new Point(DEF_VELIKOST_POLE, DEF_VELIKOST_POLE);
        private static Point _pointSize = new Point(DEF_ROZMER_BODU, DEF_ROZMER_BODU);
        private Boolean _enabled = true;
        /// <summary>
        /// Hrací pole obsahuje kolekci lodí, která zastupuje vždy sadu políček typu Loď představujících jednu loď.
        /// </summary>
        public ShipsCollection Ships;

        FieldPoint[,] políčka;

        /// <summary>
        /// Konstruktor vytvoří nové instance bodů pro zadané rozměry. Všem jsou nastaveny pozice a nastaven typ Voda.
        /// </summary>
        /// <param name="RozměryPole">Počet políček našířku a navýšku.</param>
        /// <param name="RozměryBodu">Rozměr jednoho bodu v hracím poli. Hodnota v pixelech.</param>
        public GameField(Point RozměryPole, Point RozměryBodu) {
            FieldSize = RozměryPole;
            PointSize = RozměryBodu;

            // vytvoření pole bodů
            políčka = new FieldPoint[_fieldSize.X, _fieldSize.Y];

            // vytvoření instancí každého bodu
            for(int a = 0; a < _fieldSize.X; a++)
                for(int b = 0; b < _fieldSize.Y; b++) {

                    políčka[a, b] = new FieldPoint(new Point(a, b), PointSize, this);
                    //base.Controls.Add(políčka[a, b]);
                }

            // vytvoření instance kolekce lodí
            Ships = new ShipsCollection(ref políčka);
            this.DoubleBuffered = true;
        }

        /// <summary>
        /// Konstruktor vytvoří nové instance bodů s defaultními rozměry. Všem jsou nastaveny pozice a nastaven typ Voda.
        /// </summary>
        public GameField()
            : this(_fieldSize, _pointSize) {

        }

        /// <summary>
        /// Pole Bodů reprezentujících hrací pole.
        /// </summary>
        public FieldPoint[,] Points {
            get {
                return políčka;
            }
        }

        /// <summary>
        /// Vykreslí všechny body z kolekce Políčka[,].
        /// </summary>
        /// <param name="g">Objekt Graphics, který bude použit k vekreslování.</param>
        public void Draw(Graphics g) {
            Pen okraj;
            this.Reset();
            Ships.Refresh();
            foreach(FieldPoint bod in Políčka) {
                bod.Draw(ref g);
            }

            if(_enabled)
                okraj = new Pen(Color.White, 2);
            else
                okraj = new Pen(Color.Black, 2);
            // okraj
            g.DrawRectangle(okraj, 0, 0, this.Size.Width, Size.Height);
        }

        /// <summary>
        /// Provede sestřelení políčka daného souřadnicemi index.
        /// </summary>
        /// <param name="index">Souřadnice sestřeleného bodu.</param>
        /// <returns>Vrací stav, pokud byla zasažena Loď, nebo -1 pokud bylo zasaženo moře.</returns>
        public FieldPoint.FieldPointType_ENUM Shoot(Point index) {
            if(Points[index.X, index.Y].State == FieldPoint.State_ENUM.Hit)
                return (FieldPoint.FieldPointType_ENUM)(-1);
            
            Ship l = this.Ships.Get_Reference(Points[index.X, index.Y]);

            Points[index.X, index.Y].Visibility = true;
            Points[index.X, index.Y].State = FieldPoint.State_ENUM.Hit;
            if(l != null) {
                l.Hit();
                return FieldPoint.FieldPointType_ENUM.Ship;
            }
            else
                return FieldPoint.FieldPointType_ENUM.Sea;
        }



        /// <summary>
        /// Nastaví stav všech políček na Vodu.
        /// </summary>
        public void Reset() {
            foreach(FieldPoint bod in políčka) {
                bod.Type = FieldPoint.FieldPointType_ENUM.Sea;
            }
        }

        public void ShowAllShips() {
            foreach(Ship l in this.Ships) {
                l.Visibility = true;
            }
            this.Invalidate();
        }


        /// <summary>
        /// Udává rozměry pole jako počet bodů na každé straně.
        /// </summary>
        public Point FieldSize {
            get {
                return _fieldSize;
            }
            set {
                _fieldSize = value;
                OnResize(null);
            }
        }

        /// <summary>
        /// Udává jednotnou velikost pro body v HracímPoli v pixelech.
        /// </summary>
        public Point PointSize {
            get {
                return _pointSize;
            }
            set {
                _pointSize = value;
                OnResize(null);
            }
        }

        /// <summary>
        /// Vrací 2-rozměrné pole všech bodů hracího pole.
        /// </summary>
        public FieldPoint[,] Políčka {
            get {
                return políčka;
            }
        }

        public Boolean Enabled {
            get {
                return _enabled;
            }
            set {
                _enabled = value;
                this.Refresh();
            }
        }

        private void SetBorderStyle(BorderStyle style) {
            this.BorderStyle = style;
        }
        /// <summary>
        /// ???
        /// </summary>
        /// <param name="e">=-O</param>
        protected override void OnResize(EventArgs e) {
            this.Width = _fieldSize.X * _pointSize.X;
            this.Height = _fieldSize.Y * _pointSize.Y;

            if(políčka != null)
                for(int x = 0; x <= políčka.GetUpperBound(0); x++) {
                    for(int y = 0; y <= políčka.GetUpperBound(1); y++)
                        políčka[x, y].Size = _pointSize;
                }

            base.OnResize(e);
        }


        internal Point GetIndex(int X, int Y) {
            Point temp = new Point();

            temp.X = (int)X / this.PointSize.X;
            temp.Y = (int)Y / this.PointSize.Y;
            return temp;
        }
    }

}
